package graph.editor;

import graph.util.AutomatonInputException;
import graph.util.AutomatonInputFrame;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.RectangularShape;
import java.util.Arrays;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JToolBar;

import automaton.NotDeterministicInitialStateException;
import automaton.NotDeterministicTransitionException;
import automaton.UnknownInitialStateException;

import observable.ObservableAutomaton;

public class GraphFrame extends JFrame {
	GraphComponent component;
	ObservableAutomaton<String> automaton = null;
	private FramesController controller;
	
	public GraphFrame(FramesController controller) {
		this.controller = controller;

		component = new GraphComponent();
		component.setForeground(Color.BLACK);
		component.setBackground(Color.WHITE);
		component.setOpaque(true);
		component.setPreferredSize(new Dimension(1000, 1000));
		JScrollPane scrollPane = new JScrollPane(component);

		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		JMenu menu = new JMenu(GraphEditor.MENU_FILE);
		menuBar.add(menu);
		createMenuItem(menu, GraphEditor.MENU_ITEM_NEW, new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				GraphFrame.this.controller.createFrame();
			}
		});
		createMenuItem(menu, GraphEditor.MENU_ITEM_CLOSE, new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				GraphFrame.this.controller.deleteFrame(GraphFrame.this);
			}
		});
		
		/* Added by Bien Nguyen */
		createMenuSeparator(menu);
		createMenuItem(menu, GraphEditor.MENU_ITEM_OPEN, new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				GraphFrame.this.controller.open();
			}
		});
		createMenuItem(menu, GraphEditor.MENU_ITEM_SAVE, new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				/* 
				 * We just save the Automaton which is drawn on the component
				 * through Draw function in Menu Automaton
				 */
				GraphFrame.this.controller.save(component.getInfo());
			}
		});
		/* End: Added by Bien Nguyen */
		
		createMenuSeparator(menu);
		createMenuItem(menu, GraphEditor.MENU_ITEM_QUIT, new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				GraphFrame.this.controller.quit();
			}
		});
		
		/* Added by Lam Ho */
		/* 
		 * We don't support the function which allows user can draw an Automaton
		 * by using mouse (press, drag, click) and keyboard (Alt and Spacebar).
		 * Therefore, we remove all Event Listeners on the component.
		 * However, user can draw an Automaton by choosing Draw item from menu
		 * Automaton on menu bar. Then, user must input all information of an
		 * expected Automaton
		 */
		component.removeMouseListener(component);
		component.removeMouseMotionListener(component);
		component.removeKeyListener(component);
		
		JMenu myMenu = new JMenu(GraphEditor.MENU_AUTOMATON);
		menuBar.add(myMenu);
		createMenuItem(myMenu, GraphEditor.MENU_ITEM_DRAW, new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				new AutomatonInputFrame(component);
			}
		});
		createMenuItem(myMenu, GraphEditor.MENU_ITEM_VISUALIZE, new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				String response = JOptionPane.showInputDialog(null, 
						"Enter a word to recognize");
				char[] charArray = response.toCharArray();
				String[] strArray = new String[charArray.length];
				for (int i = 0; i < charArray.length; i++) {
					strArray[i] = Character.toString(charArray[i]);
				}
				if (component.getInfo() == null) {
					JOptionPane.showMessageDialog(null, "There is no Automaton information to recognize");
					return;
				}
				try {
					automaton = AutomatonInputFrame.convertInfoIntoAutomaton(component.getInfo());
					automaton.addObserver(component);
					boolean result = automaton.recognize(strArray);
					String message = "The word " + Arrays.asList(strArray) + " is " + 
					(result? "accepted" : "not accepted");
					JOptionPane.showMessageDialog(null,  message);
					component.repaint();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
		/* End: Added by Lam Ho */
		
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				GraphFrame.this.controller.deleteFrame(GraphFrame.this);
			}
		});
		
		/* Modified by Lam Ho */
		/*JToolBar toolbar = new JToolBar();
		toolbar.setLayout(new GridLayout(0, 1));
		addShapeButton(toolbar, new Ellipse2D.Double(0, 0, 10, 10), "Small Circle");
		addShapeButton(toolbar, new Ellipse2D.Double(0, 0, 20, 20), "Big Circle");
		addShapeButton(toolbar, new Rectangle2D.Double(0, 0, 10, 10), "Small Square");
		addShapeButton(toolbar, new Rectangle2D.Double(0, 0, 20, 20), "Big Square");*/
		/* End: Modified by Lam Ho */
		
		Container contentPane = getContentPane();
		/* Modified by Lam Ho */
		//contentPane.add(toolbar, BorderLayout.WEST);
		/* End: Modified by Lam Ho */
		contentPane.add(scrollPane, BorderLayout.CENTER);
	}

	private void addShapeButton(JToolBar toolbar, final RectangularShape sample, String name) {
		JButton button = new JButton(name);
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				component.setVertexSample(sample);
			}
		});
		toolbar.add(button);
	}

	private void createMenuItem(JMenu menu, String name, ActionListener action) {
		JMenuItem menuItem = new JMenuItem(name);
		menuItem.addActionListener(action);
		menu.add(menuItem);
	}

	private void createMenuSeparator(JMenu menu) {
		JSeparator separator = new JSeparator();
		separator.setForeground(Color.lightGray);
		menu.add(separator);
	}
}
